package com.iteaj.izone.web.shiro;

import com.iteaj.izone.spi.AuthorizingService;
import com.iteaj.izone.spi.AuthzUrl;
import org.apache.shiro.mgt.RealmSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.NameableFilter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;

import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * create time: 2020/4/2
 * @author iteaj
 * @since 1.0
 */
@Configuration
@ConditionalOnClass(name = "org.apache.shiro.mgt.SecurityManager")
@ConditionalOnBean(AuthorizingService.class)
public class ShiroAutoConfiguration {

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(List<OrderShiroFilterChainDefinition> definitions
            , SecurityManager securityManager, List<NameableFilter> filters, AuthzUrl authUrl) {

        ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
        factoryBean.setSecurityManager(securityManager);

        // 权限跳转地址配置
        factoryBean.setLoginUrl(authUrl.getLoginUrl());
        factoryBean.setSuccessUrl(authUrl.getSuccessUrl());
        factoryBean.setUnauthorizedUrl(authUrl.getUnauthorizedUrl());

        // 处理过滤器
        Map<String, Filter> nameableFilterMap = filters.stream()
                .collect(Collectors.toMap(item -> item.getFilterConfig().getFilterName(), item -> item));
        factoryBean.setFilters(nameableFilterMap);

        // 处理拦截定义
        Map<String, String> pathDefinition = new LinkedHashMap<>();
        definitions.stream().forEach((definition)->pathDefinition.putAll(definition.getFilterChainMap()));
        factoryBean.setFilterChainDefinitionMap(pathDefinition);
        return factoryBean;
    }

    @Bean("ajaxFilter")
    @ConditionalOnMissingBean
    public NameableFilter AjaxFilter() {
        return new AjaxFilter();
    }

    @Order(value = 999)
    @Bean("allFilterChainDefinition")
    @ConditionalOnMissingBean(name = {"allFilterChainDefinition"})
    public OrderShiroFilterChainDefinition allFilterChainDefinition() {
        OrderShiroFilterChainDefinition chain = new OrderShiroFilterChainDefinition();

        chain.addPathDefinition("/**", "ajax,user");
        return chain;
    }

    @Bean
    public RealmSecurityManager securityManager() {
        return new DefaultWebSecurityManager();
    }
}
